/*
 * @Filename: 
 * @Author: ws
 * @Description: 
 * @Date: 2022-11-14 19:25:29
 * @LastEditTime: 2022-11-14 20:43:21
 * @Company: 662
 */
`timescale 1ns / 1ps

`define DISCARD_PHY_HEAD

module rx_gmii(
  input   wire        i_clk,
  input   wire        wrclk,
  input   wire        wr_reset,

  input   wire [7:0]  m_axis_rx_tdata,
  input   wire        m_axis_rx_tuser,
  input   wire        m_axis_rx_tvalid,

  output  reg  [7:0]  o_data_8b,
  output  reg         o_data_8b_en,
  input   wire        i_pkt_data_full
);

  parameter     idle_s    = 3'd0,
                rev_s     = 3'd1,
                discard_s = 3'd2,
                send_s    = 3'd3,
                WAIT_1_S  = 3'd4,
                DISCARD_PKT_HEAD_S  = 3'd1,
                WAIT_TAIL_S         = 3'd2;
  
  reg           wr_en;
  reg           rd_en;
  reg   [8:0]   din;
  wire  [8:0]   w_din;
  wire  [8:0]   dout;
  wire  [11:0]  data_count;
  reg           din_v;
  wire          dout_v;
  wire          empty;
  reg           wr_en_v;
  reg           rd_en_v;

  assign w_din = {~m_axis_rx_tvalid,din[7:0]};

  reg   [2:0]   rec_stat;
  reg   [2:0]   send_stat;

  always@(posedge wrclk or negedge wr_reset)
  if(!wr_reset)begin
    din   <= 9'b0;
    din_v <=  1'b0;
    wr_en <=  1'b0;
    wr_en_v <=  1'b0;
    rec_stat<=  idle_s;
  end
  else begin
    case(rec_stat)
      idle_s: begin
        wr_en <=  1'b0;
        wr_en_v <=  1'b0;
//        if(data_count[11] == 1'b1)  begin
        if(0)  begin
          if(m_axis_rx_tvalid == 1'b1)begin
            rec_stat  <=  discard_s;
            end
          else begin
            rec_stat  <=  idle_s;
          end
        end
        else begin
          if(m_axis_rx_tvalid == 1'b1)begin
            wr_en   <=  m_axis_rx_tvalid;
            din     <=  {1'b0,m_axis_rx_tdata};
            rec_stat  <=  rev_s;
          end
          else begin
            rec_stat  <=  idle_s;
          end
        end
      end

      rev_s:  begin
        wr_en   <=  m_axis_rx_tvalid;
        din     <=  {1'b0,m_axis_rx_tdata};
        if(m_axis_rx_tvalid == 1'b0) begin
          rec_stat  <=  idle_s;
          din_v     <=  1'b1;
          wr_en_v   <=  1'b1;
        end
        else  begin
          rec_stat  <=  rev_s;
        end
      end

      discard_s:  begin
        wr_en   <=  1'b0;
        if(m_axis_rx_tvalid == 1'b0) begin
          rec_stat  <=  idle_s;
        end
        else begin
          rec_stat  <=  discard_s;
        end
      end
    endcase
  end

`ifdef DISCARD_PHY_HEAD
  reg   [1:0] state_rd;
  reg   [31:0] cnt_pkt;

  always @(posedge i_clk or negedge wr_reset) begin
    if(!wr_reset) begin
      cnt_pkt               <= 32'b0;
      o_data_8b             <= 8'b0;
      o_data_8b_en          <= 1'b0;
      rd_en                 <= 1'b0;
      rd_en_v               <= 1'b0;
      state_rd              <= idle_s;
    end
    else begin
      case(state_rd)
        idle_s: begin
          o_data_8b_en        <= 1'b0;
          if(empty == 1'b0) begin
            cnt_pkt           <= cnt_pkt + 32'd1;
            rd_en_v           <= 1'b1;
            rd_en             <= 1'b1;
            state_rd          <= DISCARD_PKT_HEAD_S;          
          end
          else begin
            rd_en_v           <= 1'b0;
            rd_en             <= 1'b0;
            state_rd          <= idle_s;
          end
        end
        DISCARD_PKT_HEAD_S: begin
          rd_en_v             <= 1'b0;
          if(dout[7:0] == 8'hd5) begin
            state_rd          <= WAIT_TAIL_S;
          end
          else begin
            state_rd          <= DISCARD_PKT_HEAD_S;
          end
        end
        WAIT_TAIL_S: begin
          o_data_8b           <= dout[7:0];
          o_data_8b_en        <= 1'b1;
          
          if(dout[8] == 1'd1) begin //* end of one packet;
            rd_en             <= 1'b0;
            state_rd          <= idle_s;
          end
          else begin
            state_rd          <= WAIT_TAIL_S; 
          end
        end
        default: begin
          state_rd            <= idle_s;
        end
      endcase
        
    end
  end    
`else
  always @(posedge i_clk or negedge wr_reset)begin
    if(!wr_reset)begin
      o_data_8b            <= 8'b0;
      o_data_8b_en         <= 1'b0;
      rd_en                 <= 1'b0;
      send_stat             <= idle_s;
    end
    else begin
      case(send_stat)
        idle_s:begin
          o_data_8b        <= 8'b0;
          o_data_8b_en     <= 1'b0;
          rd_en_v           <= 1'b0;
          if(!empty)begin                   //fifo not empty,transmit frame
            if(!i_pkt_data_full)begin
              rd_en         <= 1'b1;
              send_stat     <= send_s;
            end
            else begin
              rd_en         <= 1'b0;
              send_stat     <= idle_s;
            end 
          end
          else begin                      //fifo is empty,wait at idle
            rd_en           <= 1'b0;
            send_stat       <= idle_s;
          end
        end
        send_s:begin
          o_data_8b        <= dout[7:0];
          o_data_8b_en     <= 1'b1;
          if(dout[8])begin                  //tail
            rd_en           <= 1'b0;
            rd_en_v         <= 1'b1;
            send_stat       <= WAIT_1_S;
          end
          else begin
            rd_en           <= 1'b1;
            rd_en_v         <= 1'b0;
            send_stat       <= send_s;
          end
        end
        WAIT_1_S: begin
          o_data_8b        <= 8'b0;
          o_data_8b_en     <= 1'b0;
          rd_en_v           <= 1'b0;
          send_stat         <= idle_s;
        end
      endcase
    end
  end
`endif
    
  // asfifo_9b_2048 data_fifo(
  //   .wr_clk(wrclk),               // input wire wrclk
  //   .rd_clk(i_clk),               // input wire wrclk
  //   .rst(~wr_reset),              // input wire srst
  //   .din(w_din),                  // input wire [8 : 0] din
  //   .wr_en(wr_en),                // input wire wr_en
  //   .rd_en(rd_en),                // input wire rd_en
  //   .dout(dout),                  // output wire [8 : 0] dout.
  //   .full(),                      // output wire full
  //   .empty(),                     // output wire empty
  //   .wr_data_count(data_count)    // output wire [10 : 0] data_count
  // );

  asfifo_9b_2048 data_fifo(
    .data    (w_din),         //  fifo_input.datain
    .wrreq   (wr_en),         //            .wrreq
    .rdreq   (rd_en),         //            .rdreq
    .wrclk   (wrclk),         //            .wrclk
    .rdclk   (i_clk),         //            .rdclk
    .aclr    (~wr_reset),     //            .aclr
    .q       (dout),          // fifo_output.dataout
    .wrusedw (),              //            .wrusedw
    .rdempty (),              //            .rdempty
    .wrfull  ()               //            .wrfull
  );

  // asfifo_1b_256 valid_fifo (
  //   .wr_clk(wrclk),               // input wire wrclk
  //   .rd_clk(i_clk),               // input wire wrclk
  //   .rst(~wr_reset),              // input wire srst
  //   .din(din_v),                  // input wire [0 : 0] din
  //   .wr_en(wr_en_v),              // input wire wr_en
  //   .rd_en(rd_en_v),              // input wire rd_en
  //   .dout(dout_v),                // output wire [63 : 0] dout
  //   .full(),                      // output wire full
  //   .empty(empty)                 // output wire empty
  // );

  asfifo_1b_256 valid_fifo (
    .data    (din_v),                //  fifo_input.datain
    .wrreq   (wr_en_v),              //            .wrreq
    .rdreq   (rd_en_v),              //            .rdreq
    .wrclk   (wrclk),                //            .wrclk
    .rdclk   (i_clk),                //            .rdclk
    .aclr    (~wr_reset),            //            .aclr
    .q       (dout_v),               // fifo_output.dataout
    .rdempty (empty),                //            .rdempty
    .wrfull  ()                      //            .wrfull
  );

endmodule
